using System;

namespace CalmNine.Framework 
{
    /// <summary>
    /// 可以绑定value changage委托
    /// 当变量值发生改变时执行委托函数
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class EventVal<T> : IEventVal<T>
    {
        public EventVal(T defaultValue = default) => mValue = defaultValue;

        protected T mValue;

        public static Func<T, T, bool> Comparer { get; set; } = (a, b) => a.Equals(b);

        public EventVal<T> WithComparer(Func<T, T, bool> comparer)
        {
            Comparer = comparer;
            return this;
        }

        public T Value
        {
            get => GetValue();
            set
            {
                if (value == null && mValue == null) return;
                if (value != null && Comparer(value, mValue)) return;

                SetValue(value);
            }
        }

        protected virtual void SetValue(T newValue) { 
            mValue = newValue;
            mOnValueChanged?.Invoke(newValue);
        }

        protected virtual T GetValue() => mValue;

        public void SetValueWithoutEvent(T newValue) => mValue = newValue;

        protected Action<T> mOnValueChanged = (v) => { };

        public IUnRegister Register(Action<T> onValueChanged)
        {
            mOnValueChanged += onValueChanged;
            return new EventValUnRegister<T>(this, onValueChanged);
        }

        public IUnRegister RegisterWithInit(Action<T> onValueChanged)
        {
            onValueChanged(mValue);
            return Register(onValueChanged);
        }

        public void UnRegister(Action<T> onValueChanged) => mOnValueChanged -= onValueChanged;

        IUnRegister IEasyEvent.Register(Action onEvent)
        {
            return Register(Action);
            void Action(T _) => onEvent();
        }

        /// <summary>
        /// 需要序列化成字符串，需要自定义T的ToString方法
        /// </summary>
        /// <returns></returns>
        public override string ToString() => Value.ToString();
    }

    internal class ComparerAutoRegister
    {
#if UNITY_5_6_OR_NEWER
        [UnityEngine.RuntimeInitializeOnLoadMethod(UnityEngine.RuntimeInitializeLoadType.BeforeSceneLoad)]
        public static void AutoRegister()
        {
            EventVal<int>.Comparer = (a, b) => a == b;
            EventVal<float>.Comparer = (a, b) => a == b;
            EventVal<double>.Comparer = (a, b) => a == b;
            EventVal<string>.Comparer = (a, b) => a == b;
            EventVal<long>.Comparer = (a, b) => a == b;
            EventVal<UnityEngine.Vector2>.Comparer = (a, b) => a == b;
            EventVal<UnityEngine.Vector3>.Comparer = (a, b) => a == b;
            EventVal<UnityEngine.Vector4>.Comparer = (a, b) => a == b;
            EventVal<UnityEngine.Color>.Comparer = (a, b) => a == b;
            EventVal<UnityEngine.Color32>.Comparer =
                (a, b) => a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a;
            EventVal<UnityEngine.Bounds>.Comparer = (a, b) => a == b;
            EventVal<UnityEngine.Rect>.Comparer = (a, b) => a == b;
            EventVal<UnityEngine.Quaternion>.Comparer = (a, b) => a == b;
            EventVal<UnityEngine.Vector2Int>.Comparer = (a, b) => a == b;
            EventVal<UnityEngine.Vector3Int>.Comparer = (a, b) => a == b;
            EventVal<UnityEngine.BoundsInt>.Comparer = (a, b) => a == b;
            EventVal<UnityEngine.RangeInt>.Comparer = (a, b) => a.start == b.start && a.length == b.length;
            EventVal<UnityEngine.RectInt>.Comparer = (a, b) => a.Equals(b);
        }
#endif
    }
}
